/****************************************************/
/* File: code.c                                  */
/* Yueq C Compiler		                   */
/* Author : K.C.L                                   */
/* Further Modified by Qi Yue (yueq@cse.buaa.edu.cn)*/
/****************************************************/

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "globals.h"
#include "code.h"

/* TM location number for current instruction emission */
static int emitLoc = 0 ;

/* Highest TM location emitted so far
For use in conjunction with emitSkip,
emitBackup, and emitRestore */
static int highEmitLoc = 0;

/* Procedure emitComment prints a comment line
* with comment c in the code file
*/
void emitComment( char *c )
{ 
	if (TraceCode) 
		fprintf(code,"* %s\n",c);
}

/* Procedure emitRO emits a register-only
* TM instruction
* op = the opcode
* r = target register
* s = 1st source register
* t = 2nd source register
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRO( char *op, int r, int s, int t, char *c)
{
	fprintf(code,"%3d:  %5s  %d,%d,%d ",emitLoc++,op,r,s,t);

	if (TraceCode) 
		fprintf(code,"\t%s",c) ;

	fprintf(code,"\n") ;

	if (highEmitLoc < emitLoc) 
		highEmitLoc = emitLoc ;
} /* emitRO */

/* Procedure emitRM emits a register-to-memory
* TM instruction
* op = the opcode
* r = target register
* d = the offset
* s = the base register
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRM( char *op, int r, int d, int s, char *c)
{
	fprintf(code,"%3d:  %5s  %d,%d(%d) ",emitLoc++,op,r,d,s);
	if (TraceCode) 
		fprintf(code,"\t%s",c) ;
	fprintf(code,"\n") ;
	if (highEmitLoc < emitLoc)  
		highEmitLoc = emitLoc ;
} /* emitRM */

/* Function emitSkip skips "howMany" code
* locations for later backpatch. It also
* returns the current code position
*/
int emitSkip( int howMany)
{  
	int bak = emitLoc;
	emitLoc += howMany ;
	if (highEmitLoc < emitLoc)  
		highEmitLoc = emitLoc ;
	return bak;
} /* emitSkip */

/* Procedure emitBackup backs up to
* loc = a previously skipped location
*/
void emitBackup( int loc)
{ 
	if (loc > highEmitLoc) 
		emitComment("BUG in emitBackup");
	emitLoc = loc ;
} /* emitBackup */

/* Procedure emitRestore restores the current
* code position to the highest previously
* unemitted position
*/
void emitRestore(void)
{ 
	emitLoc = highEmitLoc;
}

/* Procedure emitRM_Abs converts an absolute reference
* to a pc-relative reference when emitting a
* register-to-memory TM instruction
* op = the opcode
* r = target register
* a = the absolute location in memory
* c = a comment to be printed if TraceCode is TRUE
*/
void emitRM_Abs( char *op, int r, int a, char *c)
{ 
	fprintf(code,"%3d:  %5s  %d,%d(%d) ", emitLoc,op,r,a-(emitLoc+1),pc);
	emitLoc++;
	if (TraceCode) 
		fprintf(code,"\t%s",c) ;
	fprintf(code,"\n") ;
	if (highEmitLoc < emitLoc) 
		highEmitLoc = emitLoc ;
} /* emitRM_Abs */

